// 12.3.2 类型实参
// 类型实参（Type Arguments）是传递给模板的具体类型，用于实例化模板。类型实参的处理有一系列规则和特性，影响着模板的实例化过程。

// 基本概念
// 类型实参可以是任何有效的C++类型，包括：
// 基本类型（int, double等）
// 类类型（class, struct）
// 指针和引用类型
// 函数类型和数组类型
// 模板实例化类型
// auto（C++17起）

template <typename T>
class Container
{
    T value;
};

// 使用不同类型实参
Container<int> intContainer;
Container<std::string> stringContainer;
Container<Container<int>> nestedContainer;

// 类型实参的匹配规则
// 当将类型实参传递给模板参数时，遵循以下匹配规则：
// 1.精确匹配：
template <typename T>
class Example
{
};

Example<int> e1; // T = int

// 2.cv限定符（const/volatile）：
template <typename T>
class Example
{
};

Example<const int> e2; // T = const int

// 3.引用类型：
template <typename T>
class Example
{
};

Example<int &> e3; // T = int&

// 类型实参的推导
// 与函数模板不同，类模板通常不能自动推导类型实参（C++ 17前）：
template <typename T>
class Container
{
    T value;

public:
    Container(T val) : value(val) {}
};

// C++17前必须显式指定类型
Container<int> c1(42);

// C++17起可以推导
Container c2(42); // 推导为Container<int>

// 类型实参的限制和要求
// 类型实参必须满足模板内部对该类型的所有要求：
// 1.操作要求：
template <typename T>
T max(T a, T b)
{
    return a < b ? b : a; // 要求T支持<操作符
}

// 2.成员要求：
template <typename T>
void process(T obj)
{
    obj.method(); // 要求T有method()成员函数
}

// 3.类型特性要求：
template <typename T>
class Container
{
    typename T::value_type value; // 要求T有value_type嵌套类型
};

// 类型实参的替换和SFINAE
// 当类型实参替换到模板中时，如果导致无效代码，会触发SFINAE（Substitution Failure Is Not An Error）原则：
// 只对有size()成员的类型有效
template <typename T>
typename std::enable_if<
    has_size_member<T>::value,
    size_t>::type
getSize(T const &container)
{
    return container.size();
}

// 对其他类型有效
template <typename T>
typename std::enable_if<
    !has_size_member<T>::value,
    size_t>::type
getSize(T const &)
{
    return 0;
}

// 类型实参与模板特化
// 类型实参可以用于模板特化，为特定类型提供定制实现：
// 主模板
template <typename T>
class Serializer
{
    // 通用实现
};

// 特化版本
template <>
class Serializer<std::string>
{
    // 字符串特化实现
};